﻿using System.Collections.Generic;
using System.Windows.Markup;
using System.Linq;

using UnityConfiguration.Infrastructure;
using UnityConfiguration;

using mpu = Microsoft.Practices.Unity;

namespace UnityConfiguration
{
    /// <summary>
    /// Parent element used to configure member injection for a type.
    /// </summary>
    public class TypeInjection : TypeConfiguration, ITypeItem
    {
        /// <summary>
        /// This element is just a collection of <see cref="InjectionMemberElement"/>s. This
        /// property controls that collection.
        /// </summary>
        public List<InjectionMember> InjectionMembers {
            get {
                List<InjectionMember> members = this.Items.Cast<InjectionMember>().ToList();
                if (null != members)
                    members.ForEach(m => m.TypeResolver = this.TypeResolver); 
                return members;
            }
        }


        /// <summary>
        /// Execute this command against the given container.
        /// </summary>
        /// <remarks>
        /// Interface implementors will implement this method to
        /// apply configuration changes to the container.</remarks>
        /// <param name="container">The <see cref="IUnityContainer"/> to configure.</param>
        public override void Configure(mpu.IUnityContainer container) {
            List<mpu.InjectionMember> injections = new List<mpu.InjectionMember>();
            foreach (InjectionMember element in InjectionMembers) {
                injections.Add(element.CreateInjectionMember());
            }
            
            var serviceType = Parent.Type;
            var implementationType = Parent.MapTo;
            if (implementationType == null) {
                implementationType = serviceType;
                serviceType = null;
            }
            // this is the default behavior
            mpu.LifetimeManager lifetimeManager = new mpu.TransientLifetimeManager();
            
            container.RegisterType(serviceType, implementationType, Parent.Name, lifetimeManager, injections.ToArray());
        }
    }

    [ContentProperty("Items")]
    public abstract class TypeConfiguration : TypeResolvingObject, IContainerConfigurationCommand
    {
        private UnityType _Parent;
        private List<ITypeConfigurationItem> _Items;
        private string _ExtensionType;

        public List<ITypeConfigurationItem> Items {
            get { return _Items; }
            set { _Items = value; }
        }

        /// <summary>
        /// The <see cref="UnityType"/> that contains this element
        /// in the config file.
        /// </summary>
        internal UnityType Parent {
            get { return _Parent; }
            set { _Parent = value; }

        }
        /// <summary>
        /// Concrete type name for this configuration element.
        /// </summary>
        public string ExtensionType {
            get { return _ExtensionType; }
            set { _ExtensionType = value; }
        }

        public TypeConfiguration() {
            this.Items = new List<ITypeConfigurationItem>();
        }

        #region old
        //public List<Property> Properties {
        //    get {
        //        List<Property> properties = new List<Property>();
        //        properties = this.Items.OfType<Property>().ToList();
        //        if (null != properties)
        //            properties.ForEach(p => p.TypeResolver = this.TypeResolver); 
        //        return properties;
        //    }
        //}

        //public List<Method> Methods {
        //    get {
        //        List<Method> methods = new List<Method>();
        //        methods = this.Items.OfType<Method>().ToList();
        //        if (null != methods)
        //            methods.ForEach(p => p.TypeResolver = this.TypeResolver); ;
        //        return methods;
        //    }
        //}

        //public Constructor Constructor {
        //    get {
        //        Constructor constructor = this.Items.OfType<Constructor>().SingleOrDefault();
        //        if (null != constructor)
        //            constructor.TypeResolver = this.TypeResolver;
        //        return constructor;
        //    }
        //} 
        #endregion

        /// <summary>
        /// Execute this command against the given container.
        /// </summary>
        /// <remarks>
        /// Interface implementors will implement this method to
        /// apply configuration changes to the container.</remarks>
        /// <param name="container">The <see cref="IUnityContainer"/> to configure.</param>
        public virtual void Configure(mpu.IUnityContainer container) {

        }
    }
   
}
